package hypeerweb;

import java.util.ArrayList;
import java.util.Random;
import java.util.TreeSet;

public abstract class SendVisitor implements Visitor {
	protected static final String TARGET_KEY = "target";

	public void visit(Node node, Parameters parameters) {

		if (node.getWebId().getValue() != (Integer) parameters.get(TARGET_KEY)) {
			intermediateOperation(node, parameters);
			getNextStep(node, (Integer) parameters.get(TARGET_KEY)).accept(this, parameters);
		} else
			targetOperation(node, parameters);
	}

	private Node getNextStep(Node startNode, int targetWebIdValue) {
		TreeSet<Node> connections = new TreeSet<Node>();
		connections.addAll(startNode.getAllNeighbors());
		connections.addAll(startNode.getDownPointers());
		connections.addAll(startNode.getUpPointers());

		// Find node/s in connections with smallest distance to targetWebId
		ArrayList<Node> candidates = new ArrayList<Node>();
		int smallestDistanceSoFar = Integer.MAX_VALUE;

		for (Node node : connections) {
			WebId targetWebId = new WebId(targetWebIdValue, node.getWebId().getHeight());
			int distance = node.getWebId().distanceTo(targetWebId);

			if (distance == smallestDistanceSoFar) {
				candidates.add(node);
			} else if (distance < smallestDistanceSoFar) {
				candidates.clear();
				candidates.add(node);
				smallestDistanceSoFar = distance;
			}
		}

		return candidates.get(new Random().nextInt(candidates.size()));
	}

	public static Parameters createInitialParameters(int target) {
		Parameters p = new Parameters();
		p.set(TARGET_KEY, target);
		return p;
	}

	protected abstract void intermediateOperation(Node node, Parameters parameters);

	protected abstract void targetOperation(Node node, Parameters parameters);

}
